package edu.towson.cosc.cosc455.sliao1.markdowncompiler;
import edu.towson.cosc.cosc455.interfaces.SyntaxAnalyzer;

public class MysyntaxAnalyzer implements SyntaxAnalyzer {	
	private MylexicalAnalyzer lexical = new MylexicalAnalyzer();	
    public void document() throws CompilerException 
    {
    		lexical.getNextToken();
            if(!Compiler.token.equalsIgnoreCase("#START DOCUMENT")||!Compiler.token.equalsIgnoreCase("#start document"))
            {
            	String message = "A #START DOCUMENT annotation was expected when a " +
                                    Compiler.token + " was found!";
                throw new CompilerException(message);
            }
            else
            {
            	addToken();
            }
            lexical.getNextToken();           
            if(Compiler.token.equalsIgnoreCase("#START DEFINE"))
            {
        		define();
        		lexical.getNextToken();
        	}
        	if(Compiler.token.equalsIgnoreCase("#START HEAD"))
        	{
        		head();
        		lexical.getNextToken();
        	}        	
            body();       	
            if(!Compiler.token.equalsIgnoreCase("#END DOCUMENT"))
            {
                String message = "A #END DOCUMENT annotation was expected when a " +
                                    Compiler.token + " was found!";
                throw new CompilerException(message);
            }
            else{
            	addToken();
            }
    }  
    public void body() throws CompilerException 
    {
    	boolean endBody = false;
    	while(!endBody)
    	{
    		if(Compiler.token.equalsIgnoreCase("#START PARAGRAPH")){
    			paragraph();
    		}
    		else if(Compiler.token.equalsIgnoreCase("#START BOLD")){
    			bold();
    		}
    		else if(Compiler.token.equalsIgnoreCase("#START ITALICS")){
    			italics();    				
    		}
    		else if(Compiler.token.equalsIgnoreCase("#START LIST")){
    			list();    	
    		}
    		else if(Compiler.token.equalsIgnoreCase("#START USE")){
    			use();
    		}
    		else if(Compiler.token.equalsIgnoreCase("#NEWLINE")){
    			addToken();
    		}
    		else if(isText(Compiler.token)){
    			addToken();
    		}
    		else{
    			endBody = true;
    		}
    		if(!endBody){
    			lexical.getNextToken();
    		}
    	}       	
}
	public void head() throws CompilerException 
	{
		if(emptySpace(Compiler.token))
		{
			addToken();
			lexical.getNextToken();
		}
		if(!Compiler.token.equalsIgnoreCase("#START HEAD"))
		{
        	String message = "A #START HEAD annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }       
        lexical.getNextToken();
        title();      
        if(!Compiler.token.equalsIgnoreCase("#END HEAD"))
        {
            String message = "A #END HEAD annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }
	}
	public void title() throws CompilerException 
	{
		if(emptySpace(Compiler.token))
		{
			addToken();
			lexical.getNextToken();
		}
        if(!Compiler.token.equalsIgnoreCase("#START TITLE"))
        {
        	String message = "A #START TITLE annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }       
        lexical.getNextToken();
        if(isText(Compiler.token))
        {
        	addToken();
        }       
        if(!Compiler.token.equalsIgnoreCase("#END TITLE"))
        {
            String message = "A #END TITLE annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }
	}
	public void paragraph() throws CompilerException 
	{
		if(emptySpace(Compiler.token))
		{
			addToken();
			lexical.getNextToken();
		}
		if(!Compiler.token.equalsIgnoreCase("#START PARAGRAPH"))
		{
        	String message = "A #START PARAGRAPH annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else
		{
			addToken();
		}		
		lexical.getNextToken();		
		while(!Compiler.token.equalsIgnoreCase("#END PARAGRAPH"))
		{
			if(Compiler.token.equalsIgnoreCase("#START PARAGRAPH")){
				paragraph();
			}
			else if(Compiler.token.equalsIgnoreCase("#START DEFINE")){
				define();
			}
			else if(Compiler.token.equalsIgnoreCase("#START USE")){
				use();
			}
			else if(Compiler.token.equalsIgnoreCase("#START BOLD")){
				bold();
			}
			else if(Compiler.token.equalsIgnoreCase("#START ITALICS")){
				italics();
			}
			else if(Compiler.token.equalsIgnoreCase("#START LIST")){
				list();
			}
			else if(Compiler.token.equalsIgnoreCase("#NEWLINE")){
				addToken();
			}
			else if(isText(Compiler.token))
			{
				addToken();
			}
			else{
				String message = "Syntax error in the paragraph";
				throw new CompilerException(message);
			}			
			lexical.getNextToken();
		}       
        if(!Compiler.token.equalsIgnoreCase("#END PARAGRAPH")){
            String message = "A #END PARAGRAPH annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
    	}
	}
	public void bold() throws CompilerException {
		if(emptySpace(Compiler.token)){
			addToken();
			lexical.getNextToken();
		}
		if(!Compiler.token.equalsIgnoreCase("#START BOLD")){
        	String message = "A #START BOLD annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else{
			addToken();
		}
		
		lexical.getNextToken();	
		while(!Compiler.token.equalsIgnoreCase("#END BOLD")){
			if(Compiler.token.equalsIgnoreCase("#START DEFINE")){
				define();
			}			
			else if(Compiler.token.equalsIgnoreCase("#START USE")){
				use();
			}		
			else if(Compiler.token.equalsIgnoreCase("#START ITALICS")){
				italics();
			}
			else if(Compiler.token.equalsIgnoreCase("#NEWLINE")){
				addToken();
			}
			else if(isText(Compiler.token))
			{
				addToken();
			}
			else{
				String message = "Syntax error in bold statement";
				throw new CompilerException(message);
			}
			
			lexical.getNextToken();
		}        
        if(!Compiler.token.equalsIgnoreCase("#END BOLD")){
            String message = "A #END BOLD annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}
	public void italics() throws CompilerException {
		if(emptySpace(Compiler.token)){
			addToken();
			lexical.getNextToken();
		}
		if(!Compiler.token.equalsIgnoreCase("#START ITALICS")){
        	String message = "A #START ITALICS annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else{
			addToken();
		}		
		lexical.getNextToken();		
		while(!Compiler.token.equalsIgnoreCase("#END ITALICS"))
		{
			if(Compiler.token.equalsIgnoreCase("#START DEFINE")){
				define();
			}
			else if(Compiler.token.equalsIgnoreCase("#START USE")){
				use();
			}
			else if(Compiler.token.equalsIgnoreCase("#NEWLINE")){
				addToken();
			}
			else if(isText(Compiler.token))
			{
				addToken();
			}
			else{
				String message = "Syntax error in italics statement";
				throw new CompilerException(message);
			}
			lexical.getNextToken();
		}       
        if(!Compiler.token.equalsIgnoreCase("#END ITALICS")){
            String message = "A #END ITALICS annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}
	public void list() throws CompilerException {
		if(emptySpace(Compiler.token)){
			addToken();
			lexical.getNextToken();
		}
		if(!Compiler.token.equalsIgnoreCase("#START LIST")){
	       	String message = "A #START LIST annotation was expected when a " +
	                      Compiler.token + " was found!";
	        throw new CompilerException(message);
	    }
		else{
			addToken();
		}	        
	    lexical.getNextToken();
	    while((!Compiler.token.equals("#END LIST")) && (!Compiler.text.isEmpty())){
	       	item();
	       	lexical.getNextToken();
	    }
	    
	    if(emptySpace(Compiler.token)){
			addToken();
			lexical.getNextToken();
		}
	    if(!Compiler.token.equalsIgnoreCase("#END LIST")){
	        String message = "A #END LIST annotation was expected when a " +
	                  Compiler.token + " was found!";
	        throw new CompilerException(message);
	    }
	    else{
	       	addToken();
	    }
	}
	public void item() throws CompilerException {
		if(emptySpace(Compiler.token)){
			addToken();
			lexical.getNextToken();
		}
		if(!Compiler.token.equalsIgnoreCase("#START ITEM")){
        	String message = "A #START ITEM annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else{
			addToken();
		}
		
		lexical.getNextToken();
		while(!Compiler.token.equalsIgnoreCase("#END ITEM")){
			if(Compiler.token.equalsIgnoreCase("#START LIST")){
				list();
			}
			else if(Compiler.token.equalsIgnoreCase("#START DEFINE")){
				define();
			}
			else if(Compiler.token.equalsIgnoreCase("#START USE")){
				use();
			}
			else if(Compiler.token.equalsIgnoreCase("#NEWLINE")){
				addToken();
			}
			else if(isText(Compiler.token)){
				addToken();
			}
			else
			{
				String message = "Syntax error in item statement";
				throw new CompilerException(message);
			}
			lexical.getNextToken();
		}	
		if(emptySpace(Compiler.token))
		{
			addToken();
			lexical.getNextToken();
		}
        if(!Compiler.token.equalsIgnoreCase("#END ITEM"))
        {
            String message = "A #END ITEM annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }
	}
	@Override
	public void audio() throws CompilerException 
	{
		if(emptySpace(Compiler.token))
		{
			addToken();
			lexical.getNextToken();
		}
		 if(!Compiler.token.equalsIgnoreCase("#START AUDIO"))
		 {
	        	String message = "A #START AUDIO annotation was expected when a " +
	                                Compiler.token + " was found!";
	            throw new CompilerException(message);
		 }
		 else
		 {
			 addToken();
		 }
	        
		 lexical.getNextToken();
		 if(isText(Compiler.token))
			{
				addToken();
				lexical.getNextToken();
			}
		 if(emptySpace(Compiler.token))
		 	{
				addToken();
				lexical.getNextToken();
			}
	     if(!Compiler.token.equalsIgnoreCase("#END AUDIO"))
	     	{
	            String message = "A #END AUDIO annotation was expected when a " +
	                                Compiler.token + " was found!";
	            throw new CompilerException(message);
	        }
	     else
	     {
	    	 addToken();
	     }
	}
	@Override
	public void video() throws CompilerException 
	{
		if(emptySpace(Compiler.token))
		{
			addToken();
			lexical.getNextToken();
		}
		 if(!Compiler.token.equalsIgnoreCase("#START VIDEO"))
		 	{
	        	String message = "A #START VIDEO annotation was expected when a " +
	                                Compiler.token + " was found!";
	            throw new CompilerException(message);
	        }
		 else
		 {
			 addToken();
		 }
	        
		 lexical.getNextToken();
		 if(isText(Compiler.token))
			{
				addToken();
				lexical.getNextToken();
			}
		 
		 if(emptySpace(Compiler.token))
		 {
				addToken();
				lexical.getNextToken();
		 }
	     if(!Compiler.token.equalsIgnoreCase("#END VIDEO"))
	     {
	            String message = "A #END VIDEO annotation was expected when a " +
	                                Compiler.token + " was found!";
	            throw new CompilerException(message);
	     }
	     else
	     {
	    	 addToken();
	     }
	}
	@Override
	public void define() throws CompilerException 
	{
		if(emptySpace(Compiler.token))
		{
			addToken();
			lexical.getNextToken();
		}
		if(!Compiler.token.equalsIgnoreCase("#START DEFINE"))
		{
        	String message = "A #START DEFINE annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else
		{
			addToken();
		}
        
        lexical.getNextToken();
        if(!Compiler.token.equalsIgnoreCase("#NAME"))
        {
        	addToken();
        	String message = "A #NAME annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }
        lexical.getNextToken();
        //text
        addToken();
        
        if(!Compiler.token.equalsIgnoreCase("#VALUE"))
        {
        	String message = "A #VALUE annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }
        
        body();        
        
        if(Compiler.token.equalsIgnoreCase("#START DEFINE"))
        {
        	define();
        }
        
        if(!Compiler.token.equalsIgnoreCase("#END DEFINE"))
        {
            String message = "A #END DEFINE annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }
	}
	public void use() throws CompilerException 
	{
		if(emptySpace(Compiler.token))
		{
			addToken();
			lexical.getNextToken();
		}
        if(!Compiler.token.equalsIgnoreCase("#START USE"))
        {
        	String message = "A #START USE annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }
        
        lexical.getNextToken();
        if(isText(Compiler.token))
        {
        addToken();
        lexical.getNextToken();
        }      
        if(!Compiler.token.equalsIgnoreCase("#END USE"))
        {
            String message = "A #END USE annotation was expected when a " +
                                Compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else
        {
        	addToken();
        }
	}
	//adds the token to the stack.
		public void addToken()
		{
			Compiler.validTokens.push(Compiler.token); 
			lexical.resetLexer();
		}
		//check if string is text or tag.
		public boolean isText(String text)
		{
			boolean isText = true;
			if(text.charAt(0) == '#')
			{
				isText = false;
			}
			return isText;
		}
		//empty space string checker.
		public boolean emptySpace(String text)
		{
			boolean empty = true;
			for(int x = 0; x < text.length(); x++)
			{
				if(!lexical.isSpace(text.charAt(x)))
				{
					empty = false;
				}
			}
			return empty;
		}
}
